package com.ht.api.db.task;

import java.lang.reflect.Constructor;
import java.util.concurrent.ScheduledFuture;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.ht.api.db.Entity;
import com.ht.api.db.util.CronUtils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
 * 任务
 * @author asq
 * @createTime 2024年12月9日 13:43:43
 */
@Data
@Builder
@Slf4j
public class TaskInfo {
	/** 执行中 */
	public static final String RUNNING = "RUNNING";
	/** 已完成 */
	public static final String COMPLETED = "COMPLETED";
	/** 执行失败 */
	public static final String FAILED = "FAILED";
	/** 已停止 */
	public static final String STOPPED = "STOPPED";
	
	// 基础信息
	private long taskId; // 任务ID
	private String groupId; // 任务组ID
	private JSONObject requestParams; // 请求参数
	private String createTime; // 创建时间(秒级时间戳)
	private TaskHandler handler; // 任务执行器
	private String baseName; // 任务的基本名称
	private String name; // 任务的具体名称

	// 执行配置
	private int initialInterval; // 初始间隔(秒)
	private int maxInterval; // 最大间隔(秒)
	private double intervalMultiplier; // 间隔增长倍数
	private long maxTimes; // 最大执行时间（秒）
	private int maxNum; // 最大执行次数
	private boolean executeOnce; // 是否只执行一次
	private String startTime; // 开始执行时间(秒级时间戳)
	private String cronExpression; // 定时任务表达式

	// 执行状态
	private int attempts; // 当前执行计划下的执行次数
	private int totalAttempts; // 累计执行次数
	private String lastExecuteTime; // 最后执行时间(秒级时间戳)
	private String status; // 状态：RUNNING/COMPLETED/FAILED/STOPPED
	private String message; // 状态信息
	private boolean canceled; // 是否被标记为取消任务
	private int failAttempts; // 失败次数
	@JsonIgnore
	private ScheduledFuture<?> future; // 任务Future
	
	/**
	 * 转化为Entity,便于数据库写入
	 * @return
	 */
	public Entity toEntry() {
		Entity entity = Entity.create("db_task")
				.setMainId(taskId)
				.set("id", taskId)
				.set("group_id", groupId)
				.set("handler", handler.getClass().getName())
				.set("request_params", requestParams.toString())
				.set("create_time", createTime)
				.set("initial_interval", initialInterval)
				.set("max_interval", maxInterval)
				.set("interval_multiplier", intervalMultiplier)
				.set("max_times", maxTimes)
				.set("max_num", maxNum)
				.set("execute_once", executeOnce ? 1 : 0)
				.set("start_time", startTime)
				.set("attempts", attempts)
				.set("total_attempts", totalAttempts)
				.set("last_execute_time", lastExecuteTime)
				.set("status", status)
				.set("message", message)
				.set("cron", cronExpression)
				.set("base_name", baseName)
				.set("name", name)
				.set("fail_attempts", failAttempts)
				;
		return entity;
	}
	
	/**
	 * 从数据库Entity转化为TaskInfo实例
	 * @param entity
	 * @return
	 */
	public static TaskInfo load(Entity entity) {
		return TaskInfo.builder()
				.taskId(entity.getLong("id"))
				.groupId(entity.getStr("group_id"))
				.handler(loadTaskHandler(entity.getStr("handler")))
				.requestParams(JSONUtil.parseObj(entity.getStr("request_params")))
				.createTime(entity.getStr("create_time"))
				.initialInterval(entity.getInt("initial_interval"))
				.maxInterval(entity.getInt("max_interval"))
				.intervalMultiplier(entity.getDouble("interval_multiplier"))
				.maxTimes(entity.getInt("max_times"))
				.maxNum(entity.getInt("max_num"))
				.executeOnce(entity.getInt("execute_once") == 1)
				.startTime(entity.getStr("start_time"))
				.attempts(entity.getInt("attempts"))
				.totalAttempts(entity.getInt("total_attempts"))
				.lastExecuteTime(entity.getStr("last_execute_time"))
				.status(entity.getStr("status"))
				.message(entity.getStr("message"))
				.cronExpression(entity.getStr("cron"))
				.baseName(entity.getStr("base_name"))
				.name(entity.getStr("name"))
				.failAttempts(entity.getInt("fail_attempts"))
				.build();
	}
    
    /**
     * 根据类路径创建任务执行器
     * @param className 类的全限定名
     * @return 类的实例
     */
    public static TaskHandler loadTaskHandler(String className) {
        try {
            Class<?> clazz = Class.forName(className);
            Constructor<?> constructor = clazz.getDeclaredConstructor();
            return TaskHandler.class.cast(constructor.newInstance());
        } catch (Exception e) {
        	log.error("[task]无法创建任务执行器：{}", className, e);
        	return null;
        }
    }

    /**
     * 检查是否已经超过了cron的下一个执行时间
     */
    public boolean isExecutionCycleOver() {
        if (cronExpression == null) return false;
        
        long now = System.currentTimeMillis() / 1000;
        long nextExecutionTime = CronUtils.getNextExecutionTime(cronExpression);
        
        // 如果当前时间已经超过下次执行时间，说明已经过了当天的执行周期
        return now >= nextExecutionTime;
    }
    
    /**
     * 本轮任务是否已结束
     * @return
     */
    public boolean isOver() {
    	return (isExecuteOnce() && getAttempts() >= 1) 
    			|| (getMaxNum() > 0 && getAttempts() >= getMaxNum())
    			|| (isTimeout());
    }
    
    /**
     * 日期字符串转秒级时间戳
     * @param dateStr 日期字符串yyyy-MM-dd HH:mm:ss
     */
    public long toTimestamp(String dateStr) {
    	try {
    		return DateUtil.parse(dateStr).getTime() / 1000;
    	} catch (Exception e) {
    		return 0;
    	}
    }

	/**
	 * 检查是否已达到允许的最大执行时间
	 */
	private boolean isTimeout() {
		if (getMaxTimes() <= 0) {
			return false;
		}
		long currentTime = System.currentTimeMillis() / 1000;
		long executionTimeInSeconds = currentTime - toTimestamp(getCreateTime());
		return executionTimeInSeconds >= getMaxTimes();
	}
}
